home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Players / StillView / stillviewDlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-09  |  30.3 KB  |  1,100 lines

  1. //------------------------------------------------------------------------------
  2. // File: StillViewDlg.cpp
  3. //
  4. // Desc: DirectShow sample code - implementation of CStillViewDlg class.
  5. //
  6. // Copyright (c) 1998-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9. #include "stdafx.h"
  10. #include <atlbase.h>
  11. #include "StillView.h"
  12. #include "StillViewDlg.h"
  13. #include "mediatypes.h"
  14.  
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20.  
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CAboutDlg dialog used for App About
  23.  
  24. class CAboutDlg : public CDialog
  25. {
  26. public:
  27.     CAboutDlg();
  28.  
  29. // Dialog Data
  30.     //{{AFX_DATA(CAboutDlg)
  31.     enum { IDD = IDD_ABOUTBOX };
  32.     //}}AFX_DATA
  33.  
  34.     // ClassWizard generated virtual function overrides
  35.     //{{AFX_VIRTUAL(CAboutDlg)
  36.     protected:
  37.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  38.     //}}AFX_VIRTUAL
  39.  
  40. // Implementation
  41. protected:
  42.     //{{AFX_MSG(CAboutDlg)
  43.     //}}AFX_MSG
  44.     DECLARE_MESSAGE_MAP()
  45. };
  46.  
  47. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  48. {
  49.     //{{AFX_DATA_INIT(CAboutDlg)
  50.     //}}AFX_DATA_INIT
  51. }
  52.  
  53. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  54. {
  55.     CDialog::DoDataExchange(pDX);
  56.     //{{AFX_DATA_MAP(CAboutDlg)
  57.     //}}AFX_DATA_MAP
  58. }
  59.  
  60. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  61.     //{{AFX_MSG_MAP(CAboutDlg)
  62.         // No message handlers
  63.     //}}AFX_MSG_MAP
  64. END_MESSAGE_MAP()
  65.  
  66. /////////////////////////////////////////////////////////////////////////////
  67. // CStillViewDlg dialog
  68.  
  69. CStillViewDlg::CStillViewDlg(CWnd* pParent /*=NULL*/)
  70.     : CDialog(CStillViewDlg::IDD, pParent), m_pGB(0), m_pMC(0), m_pBV(0), m_pVW(0), m_pME(0)
  71. {
  72.     //{{AFX_DATA_INIT(CStillViewDlg)
  73.     //}}AFX_DATA_INIT
  74.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  75.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  76. }
  77.  
  78. void CStillViewDlg::DoDataExchange(CDataExchange* pDX)
  79. {
  80.     CDialog::DoDataExchange(pDX);
  81.     //{{AFX_DATA_MAP(CStillViewDlg)
  82.     DDX_Control(pDX, IDC_STATIC_FILETIME, m_StrFileTime);
  83.     DDX_Control(pDX, IDC_STATIC_IMAGESIZE, m_StrImageSize);
  84.     DDX_Control(pDX, IDC_EDIT_MEDIADIR, m_EditMediaDir);
  85.     DDX_Control(pDX, IDC_SPIN_FILES, m_SpinFiles);
  86.     DDX_Control(pDX, IDC_BUTTON_PROPPAGE, m_ButtonProperties);
  87.     DDX_Control(pDX, IDC_STATUS_DIRECTORY, m_StrMediaPath);
  88.     DDX_Control(pDX, IDC_STATIC_FILEDATE, m_StrFileDate);
  89.     DDX_Control(pDX, IDC_STATIC_FILESIZE, m_StrFileSize);
  90.     DDX_Control(pDX, IDC_LIST_PINS_OUTPUT, m_ListPinsOutput);
  91.     DDX_Control(pDX, IDC_LIST_PINS_INPUT, m_ListPinsInput);
  92.     DDX_Control(pDX, IDC_STATIC_FILELIST, m_StrFileList);
  93.     DDX_Control(pDX, IDC_MOVIE_SCREEN, m_Screen);
  94.     DDX_Control(pDX, IDC_LIST_FILTERS, m_ListFilters);
  95.     DDX_Control(pDX, IDC_LIST_FILES, m_ListFiles);
  96.     //}}AFX_DATA_MAP
  97. }
  98.  
  99. BEGIN_MESSAGE_MAP(CStillViewDlg, CDialog)
  100.     //{{AFX_MSG_MAP(CStillViewDlg)
  101.     ON_WM_ERASEBKGND()
  102.     ON_WM_SYSCOMMAND()
  103.     ON_WM_PAINT()
  104.     ON_WM_QUERYDRAGICON()
  105.     ON_WM_CLOSE()
  106.     ON_WM_DESTROY()
  107.     ON_LBN_SELCHANGE(IDC_LIST_FILES, OnSelectFile)
  108.     ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
  109.     ON_LBN_DBLCLK(IDC_LIST_FILTERS, OnDblclkListFilters)
  110.     ON_BN_CLICKED(IDC_BUTTON_PROPPAGE, OnButtonProppage)
  111.     ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_FILES, OnDeltaposSpinFiles)
  112.     ON_BN_CLICKED(IDC_BUTTON_SET_MEDIADIR, OnButtonSetMediadir)
  113.     ON_BN_CLICKED(IDC_BUTTON_GRAPHEDIT, OnButtonGraphedit)
  114.     //}}AFX_MSG_MAP
  115. END_MESSAGE_MAP()
  116.  
  117.  
  118. /////////////////////////////////////////////////////////////////////////////
  119. // CStillViewDlg message handlers
  120.  
  121. void CStillViewDlg::OnSysCommand(UINT nID, LPARAM lParam)
  122. {
  123.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  124.     {
  125.         CAboutDlg dlgAbout;
  126.         dlgAbout.DoModal();
  127.     }
  128.     else
  129.     {
  130.         CDialog::OnSysCommand(nID, lParam);
  131.     }
  132. }
  133.  
  134. // If you add a minimize button to your dialog, you will need the code below
  135. //  to draw the icon.  For MFC applications using the document/view model,
  136. //  this is automatically done for you by the framework.
  137.  
  138. void CStillViewDlg::OnPaint() 
  139. {
  140.     if (IsIconic())
  141.     {
  142.         CPaintDC dc(this); // device context for painting
  143.  
  144.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  145.  
  146.         // Center icon in client rectangle
  147.         int cxIcon = GetSystemMetrics(SM_CXICON);
  148.         int cyIcon = GetSystemMetrics(SM_CYICON);
  149.         CRect rect;
  150.         GetClientRect(&rect);
  151.         int x = (rect.Width() - cxIcon + 1) / 2;
  152.         int y = (rect.Height() - cyIcon + 1) / 2;
  153.  
  154.         // Draw the icon
  155.         dc.DrawIcon(x, y, m_hIcon);
  156.     }
  157.     else
  158.     {
  159.         CDialog::OnPaint();
  160.     }
  161. }
  162.  
  163. // The system calls this to obtain the cursor to display while the user drags
  164. //  the minimized window.
  165. HCURSOR CStillViewDlg::OnQueryDragIcon()
  166. {
  167.     return (HCURSOR) m_hIcon;
  168. }
  169.  
  170.  
  171. /////////////////////////////////////////////////////////////////////////////
  172. // CStillViewDlg DirectShow code and message handlers
  173.  
  174.  
  175. BOOL CStillViewDlg::OnInitDialog()
  176. {
  177.     CDialog::OnInitDialog();
  178.  
  179.     // Add "About..." menu item to system menu.
  180.  
  181.     // IDM_ABOUTBOX must be in the system command range.
  182.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  183.     ASSERT(IDM_ABOUTBOX < 0xF000);
  184.  
  185.     CMenu* pSysMenu = GetSystemMenu(FALSE);
  186.     if (pSysMenu != NULL)
  187.     {
  188.         CString strAboutMenu;
  189.         strAboutMenu.LoadString(IDS_ABOUTBOX);
  190.         if (!strAboutMenu.IsEmpty())
  191.         {
  192.             pSysMenu->AppendMenu(MF_SEPARATOR);
  193.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  194.         }
  195.     }
  196.  
  197.     // Set the icon for this dialog.  The framework does this automatically
  198.     //  when the application's main window is not a dialog
  199.     SetIcon(m_hIcon, TRUE);            // Set big icon
  200.     SetIcon(m_hIcon, FALSE);        // Set small icon
  201.     
  202.     // Initialize COM
  203.     CoInitialize(NULL);
  204.     
  205.     // Initialize DirectShow and query for needed interfaces
  206.     HRESULT hr = InitDirectShow();
  207.     if(FAILED(hr))
  208.     {
  209.         RetailOutput(TEXT("Failed to initialize DirectShow!  hr=0x%x\r\n"), hr);
  210.         return FALSE;
  211.     }
  212.  
  213.     // Since we're embedding video in a child window of a dialog,
  214.     // we must set the WS_CLIPCHILDREN style to prevent the bounding
  215.     // rectangle from drawing over our video frames.
  216.     m_Screen.ModifyStyle(0, WS_CLIPCHILDREN);
  217.  
  218.     // Propagate the files list and select the first item
  219.     InitMediaDirectory();
  220.    
  221.     return TRUE;  // return TRUE  unless you set the focus to a control
  222. }
  223.  
  224.  
  225. void CStillViewDlg::InitMediaDirectory(void)
  226. {
  227.     // Fill the media file list, starting with the directory passed
  228.     // on the command line.  If no directory is passed, then read the
  229.     // default media path for the DirectX SDK.
  230.     TCHAR szDir[MAX_PATH];
  231.     LONG lResult=0;
  232.  
  233.     if (theApp.m_lpCmdLine[0] == L'\0')
  234.     {
  235.         lResult = GetDXMediaPath(szDir);
  236.  
  237.         // If the DirectX SDK is not installed, use the Windows
  238.         // directory instead.
  239.         if (lResult != 0)
  240.         {
  241.             GetWindowsDirectory(szDir, MAX_PATH);
  242.             _tcscat(szDir, _T("\\") );
  243.         }
  244.     }
  245.     else
  246.         _tcscpy(szDir, theApp.m_lpCmdLine);
  247.  
  248.     TCHAR szPathMsg[MAX_PATH];
  249.     wsprintf(szPathMsg, TEXT("Media directory: %s\0"), szDir);
  250.     m_StrMediaPath.SetWindowText(szPathMsg);
  251.  
  252.     // Save current directory name
  253.     wsprintf(m_szCurrentDir, TEXT("%s\0"), szDir);
  254.  
  255.     m_EditMediaDir.SetLimitText(MAX_PATH);
  256.     m_EditMediaDir.SetWindowText(szDir);
  257.  
  258.     FillFileList(szDir);
  259. }
  260.  
  261.  
  262. LONG CStillViewDlg::GetDXMediaPath(TCHAR *szPath)
  263. {
  264.     HKEY  hKey;
  265.     DWORD dwType, dwSize = MAX_PATH;
  266.  
  267.     // Open the appropriate registry key
  268.     LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  269.                                 _T("Software\\Microsoft\\DirectX SDK"),
  270.                                 0, KEY_READ, &hKey );
  271.     if( ERROR_SUCCESS != lResult )
  272.         return -1;
  273.  
  274.     lResult = RegQueryValueEx( hKey, _T("DX81SDK Samples Path"), NULL,
  275.                               &dwType, (BYTE*)szPath, &dwSize );
  276.     RegCloseKey( hKey );
  277.  
  278.     if( ERROR_SUCCESS != lResult )
  279.         return -1;
  280.  
  281.     _tcscat( szPath, _T("\\Media\\") );
  282.     return 0;
  283. }
  284.  
  285.  
  286. void CStillViewDlg::OnButtonSetMediadir() 
  287. {
  288.     TCHAR szEditPath[MAX_PATH];
  289.     DWORD dwAttr;
  290.  
  291.     // Read the string in the media directory edit box.
  292.     m_EditMediaDir.GetWindowText(szEditPath, MAX_PATH);
  293.  
  294.     // Is this a valid directory name?
  295.     dwAttr = GetFileAttributes(szEditPath);
  296.     if ((dwAttr == (DWORD) -1) || (! (dwAttr & FILE_ATTRIBUTE_DIRECTORY)))
  297.     {
  298.         MessageBox(TEXT("Please enter a valid directory name."), TEXT("Media error"));
  299.         return;
  300.     }
  301.  
  302.     // User has specified a valid media directory.  
  303.     // Update the current path string.
  304.     TCHAR szPathMsg[MAX_PATH];
  305.     wsprintf(szPathMsg, TEXT("Media directory: %s\0"), szEditPath);
  306.     m_StrMediaPath.SetWindowText(szPathMsg);
  307.  
  308.     // Save current directory name.  Append the trailing '\' to match
  309.     // the string created by GetDXSDKMediaPath() (if not present)
  310.     int nLength = _tcslen(szEditPath);
  311.     if (szEditPath[nLength - 1] != TEXT('\\'))
  312.         wsprintf(m_szCurrentDir, TEXT("%s\\\0"), szEditPath);
  313.  
  314.     // Propagate the files list and select the first item
  315.     FillFileList(szEditPath);
  316. }
  317.  
  318.  
  319. void CStillViewDlg::FillFileList(LPTSTR pszRootDir)
  320. {
  321.     UINT attr = 0;
  322.  
  323.     // Clear current file list
  324.     m_ListFiles.ResetContent();
  325.  
  326.     // Clear filter/pin/event information listboxes
  327.     m_ListFilters.ResetContent();
  328.     m_ListPinsInput.ResetContent();
  329.     m_ListPinsOutput.ResetContent();
  330.  
  331.     ::SetCurrentDirectory(pszRootDir);
  332.  
  333.     // Add all of our known supported media types to the file list.
  334.     // Add files of each type in order.
  335.     for (int i=0; i < NUM_MEDIA_TYPES; i++)
  336.     {
  337.         m_ListFiles.Dir(attr, TypeInfo[i].pszType);
  338.     }
  339.  
  340.     // Update list box title with number of items added
  341.     int nItems  = m_ListFiles.GetCount();
  342.     TCHAR szTitle[64];
  343.     wsprintf(szTitle, TEXT("Media files (%d found)"), nItems);
  344.     m_StrFileList.SetWindowText(szTitle);
  345.  
  346.     // If there are no messages, inform the user
  347.     if (nItems == 0)
  348.         MessageBox(TEXT("This is a valid directory, but it does not contain any ")
  349.                    TEXT("media files expected by this application (BMP, GIF, JPG, TGA)."),
  350.                    TEXT("No still image files!"));
  351.     
  352.     // Automatically select the first file in the list once
  353.     // the dialog is displayed.
  354.     PostMessage(WM_FIRSTFILE, 0, 0L);
  355.     m_nCurrentFileSelection = -1;     // No selection yet
  356. }
  357.  
  358.  
  359. void CStillViewDlg::OnClose() 
  360. {
  361.     // Release DirectShow interfaces
  362.     FreeDirectShow();
  363.  
  364.     // Release COM
  365.     CoUninitialize();
  366.  
  367.     CDialog::OnClose();
  368. }
  369.  
  370. void CStillViewDlg::OnDestroy() 
  371. {
  372.     FreeDirectShow();    
  373.  
  374.     CDialog::OnDestroy();    
  375. }
  376.  
  377. void CStillViewDlg::OnSelectFile() 
  378. {
  379.     HRESULT hr;
  380.     TCHAR szFilename[MAX_PATH];
  381.  
  382.     // If this is the currently selected file, do nothing
  383.     int nItem = m_ListFiles.GetCurSel();
  384.     if (nItem == m_nCurrentFileSelection)
  385.         return;
  386.  
  387.     // Remember the current selection to speed double-click processing
  388.     m_nCurrentFileSelection = nItem;
  389.  
  390.     // Read file name from list box
  391.     m_ListFiles.GetText(nItem, szFilename);
  392.  
  393.     // First release any existing interfaces
  394.     ResetDirectShow();
  395.  
  396.     // Clear filter/pin/event information listboxes
  397.     m_ListFilters.ResetContent();
  398.     m_ListPinsInput.ResetContent();
  399.     m_ListPinsOutput.ResetContent();
  400.  
  401.     // Load the selected media file
  402.     hr = PrepareMedia(szFilename);
  403.     if (FAILED(hr))
  404.     {
  405.         MessageBeep(0);
  406.         return;
  407.     }
  408.  
  409.     // Display useful information about this file
  410.     DisplayFileInfo(szFilename);
  411.     DisplayImageInfo();
  412.  
  413.     // Enumerate and display filters in graph
  414.     hr = EnumFilters();
  415.  
  416.     // Select the first filter in the list to display pin info
  417.     m_ListFilters.SetCurSel(0);
  418.     OnSelchangeListFilters();
  419. }
  420.  
  421.  
  422. HRESULT CStillViewDlg::PrepareMedia(LPTSTR lpszMovie)
  423. {
  424.     USES_CONVERSION;
  425.     HRESULT hr = S_OK;
  426.  
  427.     // Allow DirectShow to create the FilterGraph for this media file
  428.     hr = m_pGB->RenderFile(T2W(lpszMovie), NULL);
  429.     if (FAILED(hr)) {
  430.         RetailOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"),
  431.                  hr, lpszMovie);
  432.         return hr;
  433.     }
  434.  
  435.     // Set the message drain of the video window to point to our main
  436.     // application window.
  437.     hr = m_pVW->put_MessageDrain((OAHWND) m_hWnd);
  438.  
  439.     // Have the graph signal event via window callbacks
  440.     hr = m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
  441.  
  442.     // Place video window within the bounding rectangle
  443.     CenterVideo();
  444.  
  445.     // Finish configuring video window
  446.     hr = m_pVW->put_WindowStyle(WS_CHILD);
  447.     hr = m_pVW->put_Owner((OAHWND) m_Screen.GetSafeHwnd());
  448.     hr = m_pVW->SetWindowForeground(-1);
  449.  
  450.     // Display the media file's first frame, which is the only frame
  451.     // for a still image.
  452.     hr = m_pMC->Pause();
  453.  
  454.     return hr;
  455. }
  456.  
  457. HRESULT CStillViewDlg::InitDirectShow(void)
  458. {
  459.     HRESULT hr = S_OK;
  460.  
  461.     // Zero interfaces (sanity check)
  462.     m_pVW = NULL;
  463.     m_pBV = NULL;
  464.  
  465.     JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB));
  466.     JIF(m_pGB->QueryInterface(IID_IMediaControl,  (void **)&m_pMC));
  467.     JIF(m_pGB->QueryInterface(IID_IBasicVideo,    (void **)&m_pBV));
  468.     JIF(m_pGB->QueryInterface(IID_IVideoWindow,   (void **)&m_pVW));
  469.     JIF(m_pGB->QueryInterface(IID_IMediaEventEx,  (void **)&m_pME));
  470.  
  471.     return S_OK;
  472.  
  473. CLEANUP:
  474.     FreeDirectShow();
  475.     return(hr);
  476. }
  477.  
  478. HRESULT CStillViewDlg::FreeDirectShow(void)
  479. {
  480.     HRESULT hr=S_OK;
  481.  
  482.     // Hide video window and remove owner.  This is not necessary here,
  483.     // since we are about to destroy the filter graph, but it is included
  484.     // for demonstration purposes.  Remember to hide the video window and
  485.     // clear its owner when destroying a window that plays video.
  486.     if(m_pVW)
  487.     {
  488.         hr = m_pVW->put_Visible(OAFALSE);
  489.         hr = m_pVW->put_Owner(NULL);
  490.     }
  491.  
  492.     SAFE_RELEASE(m_pMC);
  493.     SAFE_RELEASE(m_pVW);
  494.     SAFE_RELEASE(m_pBV);
  495.     SAFE_RELEASE(m_pME);
  496.     SAFE_RELEASE(m_pGB);
  497.  
  498.     return hr;
  499. }
  500.  
  501. void CStillViewDlg::ResetDirectShow(void)
  502. {
  503.     // Destroy the current filter graph its filters.
  504.     FreeDirectShow();
  505.  
  506.     // Reinitialize graph builder and query for interfaces
  507.     InitDirectShow();
  508. }
  509.  
  510. void CStillViewDlg::CenterVideo(void)
  511. {
  512.     LONG width, height;
  513.     HRESULT hr;
  514.  
  515.     if (!m_pVW)
  516.         return;
  517.  
  518.     // Read coordinates of video container window
  519.     RECT rc;
  520.     m_Screen.GetClientRect(&rc);
  521.     width =  rc.right - rc.left;
  522.     height = rc.bottom - rc.top;
  523.  
  524.     // Ignore the video's original size and stretch to fit bounding rectangle
  525.     hr = m_pVW->SetWindowPosition(rc.left, rc.top, width, height);
  526.     if (FAILED(hr))
  527.     {
  528.         RetailOutput(TEXT("Failed to set window position!  hr=0x%x\r\n"), hr);
  529.         return;
  530.     }
  531. }
  532.  
  533.  
  534. LRESULT CStillViewDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  535. {
  536.     // Field notifications from the DirectShow filter graph manager
  537.     // and those posted by the application
  538.     switch (message)
  539.     {
  540.         case WM_GRAPHNOTIFY:
  541.             HandleGraphEvent();
  542.             break;
  543.  
  544.         case WM_PLAYFILE:
  545.             PlaySelectedFile();
  546.             break;
  547.  
  548.         case WM_NEXTFILE:
  549.             PlayNextFile();
  550.             break;
  551.  
  552.         case WM_PREVIOUSFILE:
  553.             PlayPreviousFile();
  554.             break;
  555.  
  556.         case WM_FIRSTFILE:
  557.             // Select the first item in the list
  558.             m_ListFiles.SetCurSel(0);
  559.             OnSelectFile();
  560.             break;
  561.     }
  562.  
  563.     // Pass along this message to the video window, which exists as a child
  564.     // of the m_Screen window.  This method should be used by windows that 
  565.     // make a renderer window a child window. It forwards significant messages 
  566.     // to the child window that the child window would not otherwise receive. 
  567.     if (m_pVW)
  568.     {
  569.         m_pVW->NotifyOwnerMessage((LONG_PTR) m_hWnd, message, wParam, lParam);
  570.     }
  571.  
  572.     return CDialog::WindowProc(message, wParam, lParam);
  573. }
  574.  
  575.  
  576. HRESULT CStillViewDlg::HandleGraphEvent(void)
  577. {
  578.     LONG evCode, evParam1, evParam2;
  579.     HRESULT hr=S_OK;
  580.  
  581.     while(SUCCEEDED(m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1, 
  582.                                  (LONG_PTR *) &evParam2, 0)))
  583.     {
  584.         // Spin through the events
  585.         hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
  586.     }
  587.  
  588.     return hr;
  589. }
  590.  
  591. void CStillViewDlg::PlaySelectedFile() 
  592. {
  593.     OnSelectFile();
  594. }
  595.  
  596. void CStillViewDlg::OnDeltaposSpinFiles(NMHDR* pNMHDR, LRESULT* pResult) 
  597. {
  598.     NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
  599.  
  600.     if (pNMUpDown->iDelta > 0)
  601.         PostMessage(WM_NEXTFILE, 0, 0L);
  602.     else
  603.         PostMessage(WM_PREVIOUSFILE, 0, 0L);
  604.  
  605.     *pResult = 0;
  606. }
  607.  
  608. void CStillViewDlg::PlayNextFile(void)
  609. {
  610.     int nItems  = m_ListFiles.GetCount();
  611.     
  612.     // Return if the list is empty
  613.     if (!nItems)
  614.         return;
  615.         
  616.     int nCurSel = m_ListFiles.GetCurSel();
  617.     int nNewSel = (nCurSel + 1) % nItems;
  618.  
  619.     // Select the next item in the list, wrapping to top if needed
  620.     m_ListFiles.SetCurSel(nNewSel);
  621.     OnSelectFile();
  622. }
  623.  
  624.  
  625. void CStillViewDlg::PlayPreviousFile(void)
  626. {
  627.     int nItems  = m_ListFiles.GetCount();
  628.  
  629.     // Return if the list is empty
  630.     if (!nItems)
  631.         return;
  632.         
  633.     int nCurSel = m_ListFiles.GetCurSel();
  634.     int nNewSel = nCurSel - 1;
  635.  
  636.     // If moved off top of list, select last item in list
  637.     if (nNewSel < 0)
  638.         nNewSel = nItems - 1;
  639.  
  640.     // Select the next item in the list, wrapping to top if needed
  641.     m_ListFiles.SetCurSel(nNewSel);
  642.     OnSelectFile();
  643. }
  644.  
  645.  
  646. HRESULT CStillViewDlg::EnumFilters (void) 
  647. {
  648.     USES_CONVERSION;
  649.  
  650.     HRESULT hr;
  651.     IEnumFilters *pEnum = NULL;
  652.     IBaseFilter *pFilter = NULL;
  653.     ULONG cFetched;
  654.  
  655.     // Clear filters list box
  656.     m_ListFilters.ResetContent();
  657.     
  658.     // Get filter enumerator
  659.     hr = m_pGB->EnumFilters(&pEnum);
  660.     if (FAILED(hr))
  661.     {
  662.         m_ListFilters.AddString(TEXT("<ERROR>"));
  663.         return hr;
  664.     }
  665.  
  666.     // Enumerate all filters in the graph
  667.     while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
  668.     {
  669.         FILTER_INFO FilterInfo;
  670.         TCHAR szName[256];
  671.         
  672.         hr = pFilter->QueryFilterInfo(&FilterInfo);
  673.         if (FAILED(hr))
  674.         {
  675.             m_ListFilters.AddString(TEXT("<ERROR>"));
  676.         }
  677.         else
  678.         {
  679.             // Add the filter name to the filters listbox
  680.             lstrcpy(szName, W2T(FilterInfo.achName));
  681.             m_ListFilters.AddString(szName);
  682.  
  683.             FilterInfo.pGraph->Release();
  684.         }       
  685.         pFilter->Release();
  686.     }
  687.     pEnum->Release();
  688.  
  689.     return hr;
  690. }
  691.  
  692.  
  693. //
  694. // The GraphBuilder interface provides a FindFilterByName() method,
  695. // which provides similar functionality to the method below.
  696. // This local method is provided for educational purposes.
  697. //
  698. IBaseFilter *CStillViewDlg::FindFilterFromName(LPTSTR szNameToFind)
  699. {
  700.     USES_CONVERSION;
  701.  
  702.     HRESULT hr;
  703.     IEnumFilters *pEnum = NULL;
  704.     IBaseFilter *pFilter = NULL;
  705.     ULONG cFetched;
  706.     BOOL bFound = FALSE;
  707.  
  708.     // Get filter enumerator
  709.     hr = m_pGB->EnumFilters(&pEnum);
  710.     if (FAILED(hr))
  711.         return NULL;
  712.  
  713.     // Enumerate all filters in the graph
  714.     while((pEnum->Next(1, &pFilter, &cFetched) == S_OK) && (!bFound))
  715.     {
  716.         FILTER_INFO FilterInfo;
  717.         TCHAR szName[256];
  718.         
  719.         hr = pFilter->QueryFilterInfo(&FilterInfo);
  720.         if (FAILED(hr))
  721.         {
  722.             pFilter->Release();
  723.             pEnum->Release();
  724.             return NULL;
  725.         }
  726.  
  727.         // Compare this filter's name with the one we want
  728.         lstrcpy(szName, W2T(FilterInfo.achName));
  729.         if (! lstrcmp(szName, szNameToFind))
  730.         {
  731.             bFound = TRUE;
  732.         }
  733.  
  734.         FilterInfo.pGraph->Release();
  735.  
  736.         // If we found the right filter, don't release its interface.
  737.         // The caller will use it and release it later.
  738.         if (!bFound)
  739.             pFilter->Release();
  740.         else
  741.             break;
  742.     }
  743.     pEnum->Release();
  744.  
  745.     return (bFound ? pFilter : NULL);
  746. }
  747.  
  748.  
  749. HRESULT CStillViewDlg::EnumPins(IBaseFilter *pFilter, PIN_DIRECTION PinDir,
  750.                               CListBox& Listbox)
  751. {
  752.     HRESULT hr;
  753.     IEnumPins  *pEnum = NULL;
  754.     IPin *pPin = NULL;
  755.  
  756.     // Clear the specified listbox (input or output)
  757.     Listbox.ResetContent();
  758.  
  759.     // Get pin enumerator
  760.     hr = pFilter->EnumPins(&pEnum);
  761.     if (FAILED(hr))
  762.     {
  763.         Listbox.AddString(TEXT("<ERROR>"));
  764.         return hr;
  765.     }
  766.  
  767.     // Enumerate all pins on this filter
  768.     while(pEnum->Next(1, &pPin, 0) == S_OK)
  769.     {
  770.         PIN_DIRECTION PinDirThis;
  771.  
  772.         hr = pPin->QueryDirection(&PinDirThis);
  773.         if (FAILED(hr))
  774.         {
  775.             Listbox.AddString(TEXT("<ERROR>"));
  776.             pPin->Release();
  777.             continue;
  778.         }
  779.  
  780.         // Does the pin's direction match the requested direction?
  781.         if (PinDir == PinDirThis)
  782.         {
  783.             PIN_INFO pininfo={0};
  784.  
  785.             // Direction matches, so add pin name to listbox
  786.             hr = pPin->QueryPinInfo(&pininfo);
  787.             if (SUCCEEDED(hr))
  788.             {
  789.                 CString str(pininfo.achName);
  790.                 Listbox.AddString(str);
  791.             }
  792.  
  793.             // The pininfo structure contains a reference to an IBaseFilter,
  794.             // so you must release its reference to prevent resource a leak.
  795.             pininfo.pFilter->Release();
  796.         }
  797.         pPin->Release();
  798.     }
  799.     pEnum->Release();
  800.  
  801.     return hr;
  802. }
  803.  
  804.  
  805. void CStillViewDlg::OnSelchangeListFilters() 
  806. {
  807.     HRESULT hr;
  808.     IBaseFilter *pFilter = NULL;
  809.     TCHAR szNameToFind[128];
  810.  
  811.     // Read the current filter name from the list box
  812.     int nCurSel = m_ListFilters.GetCurSel();
  813.     m_ListFilters.GetText(nCurSel, szNameToFind);
  814.  
  815.     // Read the current list box name and find it in the graph
  816.     pFilter = FindFilterFromName(szNameToFind);
  817.     if (!pFilter)
  818.         return;
  819.  
  820.     // Now that we have filter information, enumerate pins by direction
  821.     // and add their names to the appropriate listboxes
  822.     hr = EnumPins(pFilter, PINDIR_INPUT,  m_ListPinsInput);
  823.     hr = EnumPins(pFilter, PINDIR_OUTPUT, m_ListPinsOutput);
  824.  
  825.     // Find out if this filter supports a property page
  826.     if (SupportsPropertyPage(pFilter))
  827.         m_ButtonProperties.EnableWindow(TRUE);
  828.     else
  829.         m_ButtonProperties.EnableWindow(FALSE);
  830.     
  831.     // Must release the filter interface returned from FindFilterByName()
  832.     pFilter->Release();
  833. }
  834.  
  835.  
  836. BOOL CStillViewDlg::DisplayImageInfo(void)
  837. {
  838.     HRESULT hr;
  839.     long lWidth, lHeight;
  840.     
  841.     if (!m_pBV)
  842.         return FALSE;
  843.  
  844.     hr = m_pBV->GetVideoSize(&lWidth, &lHeight);
  845.     if (SUCCEEDED(hr))
  846.     {
  847.         TCHAR szSize[64];
  848.         wsprintf(szSize, TEXT("Image size: %d x %d\0"), lWidth, lHeight);
  849.         m_StrImageSize.SetWindowText(szSize);
  850.     }
  851.  
  852.     return TRUE;
  853. }
  854.  
  855. BOOL CStillViewDlg::DisplayFileInfo(LPTSTR szFile)
  856. {
  857.     HANDLE hFile;
  858.     LONGLONG llSize=0;
  859.     DWORD dwSizeLow=0, dwSizeHigh=0;
  860.     TCHAR szScrap[64];
  861.  
  862.     // Open the specified file to read size and date information
  863.     hFile = CreateFile(szFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
  864.                        (DWORD) 0, NULL);
  865.  
  866.     if (hFile == INVALID_HANDLE_VALUE)
  867.     {
  868.         RetailOutput(TEXT("*** Failed(0x%x) to open file (to read size)!\r\n"),
  869.                      GetLastError());
  870.         return FALSE;
  871.     }
  872.  
  873.     dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
  874.     if ((dwSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
  875.     {
  876.         RetailOutput(TEXT("*** Error(0x%x) reading file size!\r\n"),
  877.                      GetLastError());
  878.         CloseHandle(hFile);
  879.         return FALSE;
  880.     }
  881.  
  882.     // Large files will also use the upper DWORD to report size.
  883.     // Add them together for the true size if necessary.
  884.     if (dwSizeHigh)
  885.         llSize = (dwSizeHigh << 16) + dwSizeLow;
  886.     else
  887.         llSize = dwSizeLow;
  888.  
  889.     // Read date information
  890.     BY_HANDLE_FILE_INFORMATION fi;
  891.     if (GetFileInformationByHandle(hFile, &fi))
  892.     {
  893.         CTime time(fi.ftLastWriteTime);
  894.  
  895.         wsprintf(szScrap, TEXT("Date: %02d/%02d/%d\0"), 
  896.                  time.GetMonth(), time.GetDay(), time.GetYear());
  897.         m_StrFileDate.SetWindowText(szScrap);
  898.  
  899.         // Set time.  Note that 12am-12:59am will show as "00" instead of 12.
  900.         wsprintf(szScrap, TEXT("Time: %02d:%02d %s\0"), 
  901.                 (time.GetHour() % 12), time.GetMinute(), 
  902.                 ((time.GetHour() > 12) ? TEXT("pm\0") : TEXT("am\0")));
  903.         m_StrFileTime.SetWindowText(szScrap);
  904.     }
  905.  
  906.     CloseHandle(hFile);
  907.  
  908.     // Update size/date windows
  909.     wsprintf(szScrap, TEXT("Size: %d bytes\0"), dwSizeLow);
  910.     m_StrFileSize.SetWindowText(szScrap);
  911.  
  912.     return TRUE;
  913. }
  914.  
  915.  
  916. BOOL CStillViewDlg::SupportsPropertyPage(IBaseFilter *pFilter) 
  917. {
  918.     HRESULT hr;
  919.     TCHAR szNameToFind[128];
  920.     ISpecifyPropertyPages *pSpecify;
  921.  
  922.     // Read the current filter name from the list box
  923.     int nCurSel = m_ListFilters.GetCurSel();
  924.     m_ListFilters.GetText(nCurSel, szNameToFind);
  925.  
  926.     // Discover if this filter contains a property page
  927.     hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
  928.     if (SUCCEEDED(hr)) 
  929.     {
  930.         pSpecify->Release();
  931.         return TRUE;
  932.     }
  933.     else
  934.         return FALSE;
  935. }
  936.  
  937.  
  938. void CStillViewDlg::OnButtonProppage() 
  939. {
  940.     HRESULT hr;
  941.     IBaseFilter *pFilter = NULL;
  942.     TCHAR szNameToFind[128];
  943.     ISpecifyPropertyPages *pSpecify;
  944.  
  945.     // Read the current filter name from the list box
  946.     int nCurSel = m_ListFilters.GetCurSel();
  947.     m_ListFilters.GetText(nCurSel, szNameToFind);
  948.  
  949.     // Read the current list box name and find it in the graph
  950.     pFilter = FindFilterFromName(szNameToFind);
  951.     if (!pFilter)
  952.         return;
  953.  
  954.     // Discover if this filter contains a property page
  955.     hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
  956.     if (SUCCEEDED(hr)) 
  957.     {
  958.         do 
  959.         {
  960.             FILTER_INFO FilterInfo;
  961.             hr = pFilter->QueryFilterInfo(&FilterInfo);
  962.             if (FAILED(hr))
  963.                 break;
  964.  
  965.             CAUUID caGUID;
  966.             hr = pSpecify->GetPages(&caGUID);
  967.             if (FAILED(hr))
  968.                 break;
  969.  
  970.             pSpecify->Release();
  971.         
  972.             // Display the filter's property page
  973.             OleCreatePropertyFrame(
  974.                 m_hWnd,                 // Parent window
  975.                 0,                      // x (Reserved)
  976.                 0,                      // y (Reserved)
  977.                 FilterInfo.achName,     // Caption for the dialog box
  978.                 1,                      // Number of filters
  979.                 (IUnknown **)&pFilter,  // Pointer to the filter 
  980.                 caGUID.cElems,          // Number of property pages
  981.                 caGUID.pElems,          // Pointer to property page CLSIDs
  982.                 0,                      // Locale identifier
  983.                 0,                      // Reserved
  984.                 NULL                    // Reserved
  985.             );
  986.             CoTaskMemFree(caGUID.pElems);
  987.             FilterInfo.pGraph->Release(); 
  988.  
  989.         } while(0);
  990.     }
  991.  
  992.     pFilter->Release();
  993. }
  994.  
  995.  
  996. void CStillViewDlg::OnDblclkListFilters() 
  997. {
  998.     OnButtonProppage();
  999. }
  1000.  
  1001.  
  1002. void RetailOutput(TCHAR *tszErr, ...)
  1003. {
  1004.     TCHAR tszErrOut[MAX_PATH + 256];
  1005.  
  1006.     va_list valist;
  1007.  
  1008.     va_start(valist,tszErr);
  1009.     wvsprintf(tszErrOut, tszErr, valist);
  1010.     OutputDebugString(tszErrOut);
  1011.     va_end (valist);
  1012. }
  1013.  
  1014.  
  1015. LONG CStillViewDlg::GetGraphEditPath(TCHAR *szPath)
  1016. {
  1017.     HKEY  hKey;
  1018.     DWORD dwType, dwSize = MAX_PATH;
  1019.  
  1020.     // Open the appropriate registry key
  1021.     LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1022.                                 _T("Software\\Microsoft\\Shared Tools\\Graphedit"),
  1023.                                 0, KEY_READ, &hKey );
  1024.     if( ERROR_SUCCESS != lResult )
  1025.         return -1;
  1026.  
  1027.     // Read the full path (including .exe name) for the GraphEdit tool
  1028.     lResult = RegQueryValueEx( hKey, _T("Path"), NULL,
  1029.                               &dwType, (BYTE*)szPath, &dwSize );
  1030.     RegCloseKey( hKey );
  1031.  
  1032.     if( ERROR_SUCCESS != lResult )
  1033.         return -1;
  1034.  
  1035.     return 0;
  1036. }
  1037.  
  1038.  
  1039. void CStillViewDlg::OnButtonGraphedit() 
  1040. {
  1041.     TCHAR szFilename[128], szFile[MAX_PATH];
  1042.  
  1043.     // Read file name from list box
  1044.     int nItem = m_ListFiles.GetCurSel();
  1045.     m_ListFiles.GetText(nItem, szFilename);
  1046.  
  1047.     // Build the full file name with path.  The path will already have
  1048.     // a '\' appended to the end.
  1049.     wsprintf(szFile, TEXT("%s%s\0"), m_szCurrentDir, szFilename);
  1050.  
  1051.     // Launch GraphEdit for the selected file
  1052.     //    
  1053.     // First look for a registry key containing its full path
  1054.     TCHAR szPath[MAX_PATH];
  1055.  
  1056.     LONG lResult = GetGraphEditPath(szPath);
  1057.  
  1058.     // If the DirectX SDK is not installed, just look for GraphEdit
  1059.     // anywhere in the system path.
  1060.     if (lResult != 0)
  1061.     {
  1062.         wsprintf(szPath, TEXT("%s\0"), TEXT("graphedt\0"));
  1063.     }
  1064.  
  1065.     // Lauch GraphEdit using either the full tool path or just its name                               
  1066.     HINSTANCE rc = ShellExecute(m_hWnd, TEXT("open\0"), szPath, 
  1067.                                 szFile, NULL, SW_SHOWNORMAL);
  1068.  
  1069.     if (rc < (HINSTANCE) 32)
  1070.     {
  1071.         // Failed to start the app
  1072.         if ((rc == (HINSTANCE) ERROR_FILE_NOT_FOUND) || 
  1073.             (rc == (HINSTANCE) ERROR_PATH_NOT_FOUND))
  1074.         {
  1075.             MessageBox(TEXT("Couldn't find the GraphEdit application.\r\n\r\n")
  1076.                        TEXT("Please copy graphedt.exe to a directory on your path."), 
  1077.                        TEXT("Can't find GraphEdit"));   
  1078.         }
  1079.     }
  1080. }
  1081.  
  1082. BOOL CStillViewDlg::OnEraseBkgnd(CDC *pDC)
  1083. {
  1084.     // Intercept background erasing for the movie window, since the
  1085.     // video renderer will keep the screen painted.  Without this code,
  1086.     // your video window might get painted over with gray (the default
  1087.     // background brush) when it is obscured by another window and redrawn.
  1088.     CRect rc;
  1089.  
  1090.     // Get the bounding rectangle for the movie screen
  1091.     m_Screen.GetWindowRect(&rc);
  1092.     ScreenToClient(&rc);
  1093.  
  1094.     // Exclude the clipping region occupied by our movie screen
  1095.     pDC->ExcludeClipRect(&rc);
  1096.     
  1097.     // Erase the remainder of the dialog as usual
  1098.     return CDialog::OnEraseBkgnd(pDC);
  1099. }
  1100.